﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

namespace H.PK
{
    public class HPackRecord
    {
        /// <summary>
        /// 
        /// </summary>
        private readonly string _File;

        /// <summary>
        /// 存储映射关系
        /// </summary>
        private readonly Dictionary<string, string> _Dict = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

        /// <summary>
        /// 索引文件名称
        /// </summary>
        public const string IndexFileName = "00000000.hpk";

        /// <summary>
        /// 获取所有已经安装的包
        /// </summary>
        public IEnumerable<KeyValuePair<string, string>> Installed => _Dict;

        /// <summary>
        /// 互斥体,用于同步对IndexFile的修改,避免脏读脏写
        /// </summary>
        private readonly Mutex Mutex = new Mutex(false, "HPM_Mutex");

        public HPackRecord(string file)
        {
            _File = file;
            Load();
        }

        /// <summary>
        /// 加载记录文件
        /// </summary>
        public void Load()
        {
            if (!File.Exists(_File))
            {
                return;
            }
            HEncoding encoding = new HEncoding();
            try
            {
                Mutex.WaitOne();
                using (BinaryReader reader = new BinaryReader(new FileStream(_File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), encoding))
                {
                    byte mask = reader.ReadByte();
                    encoding.Mask = mask;

                    while (reader.BaseStream.Length != reader.BaseStream.Position)
                    {
                        string realName = reader.ReadString();      //包名称
                        string randomName = reader.ReadString();    //随机名称
                        _Dict[realName] = randomName;
                    }
                }
            }
            catch (EndOfStreamException) { }
            finally
            {
                Mutex.ReleaseMutex();
            }
        }

        /// <summary>
        /// 给定一个RealName,创建一个假名称
        /// </summary>
        /// <param name="realName">传入真名称</param>
        /// <returns>返回假名称</returns>
        public string NewPack(string realName)
        {
            string pluginDir = Path.GetDirectoryName(_File);
            if (!Directory.Exists(pluginDir))
            {
                Directory.CreateDirectory(pluginDir);
            }
            HEncoding encoding = new HEncoding();

            try
            {
                Mutex.WaitOne();
                Random random = new Random((int)DateTime.Now.Ticks);
                using (FileStream fs = new FileStream(_File, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    if (File.Exists(_File))
                    {
                        BinaryReader reader = null;
                        try
                        {
                            reader = new BinaryReader(fs, encoding);
                            byte mask = reader.ReadByte();
                            encoding.Mask = mask;

                            while (reader.BaseStream.Length != reader.BaseStream.Position)
                            {
                                string realName2 = reader.ReadString();    //包名称
                                string fakeName2 = reader.ReadString();    //随机名称
                                if (StringComparer.CurrentCultureIgnoreCase.Equals(realName, realName2))
                                {
                                    return fakeName2;
                                }
                                _Dict[realName2] = fakeName2;
                            }
                        }
                        catch (EndOfStreamException) { }
                        finally
                        {
                            fs.Seek(0, SeekOrigin.Begin);
                        }
                    }
                    string fakeName = null;
                    do
                    {
                        fakeName = (random.Next() % 100000000).ToString().PadLeft(8, '0');
                    } while (_Dict.ContainsKey(fakeName) || File.Exists(Path.Combine(pluginDir, fakeName + ".hpk")));

                    _Dict.Add(realName, fakeName);

                    BinaryWriter writer = new BinaryWriter(fs, encoding);

                    encoding.Mask = (byte)(random.Next() % 256);
                    writer.Write(encoding.Mask);

                    foreach (KeyValuePair<string, string> kv in _Dict)
                    {
                        writer.Write(kv.Key);
                        writer.Write(kv.Value);
                    }

                    return fakeName;
                }
            }
            finally
            {
                Mutex.ReleaseMutex();
            }
        }

        /// <summary>
        /// 获取真实名称
        /// </summary>
        public string GetRealName(string fakeName)
        {
            return _Dict.Where(kv => _Dict.Comparer.Equals(kv.Value, fakeName)).Select(kv => kv.Key).FirstOrDefault();
        }

        /// <summary>
        /// 获取某个RealName对应的假名称
        /// </summary>
        /// <returns></returns>
        public string GetFakeName(string realName)
        {
            _Dict.TryGetValue(realName, out string value);
            return value;
        }


    }
}
